#include "LecteurPhraseAvecTable.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecTable::LecteurPhraseAvecTable(string nomFich) :
	ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::analyse() {
	programme();
	cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::programme() {
// <programme> ::= debut <seqInst> fin <EOF>

	sauterSymCour("debut");
	seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::seqInst() {
// <seqIns> ::= <inst> ; { <inst> ; }

	do {
		inst();
		sauterSymCour(";");
	} while((ls.getSymCour()=="<VARIABLE>") || 
                (ls.getSymCour()=="si") || 
                (ls.getSymCour()=="tantque") || 
                (ls.getSymCour()=="repeter")  || 
                (ls.getSymCour()=="ecrire")  || 
                (ls.getSymCour()=="lire") ||
                (ls.getSymCour()=="pour")||
                (ls.getSymCour()=="switch"));
	// tant que le symbole courant est un debut possible d'instruction...
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::inst() {
// <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter> | <instLire> | <instEcrire> | <instPour> 

	if (ls.getSymCour()=="<VARIABLE>"){
            affectation() ;
        }
        else if (ls.getSymCour()=="si"){
            instSi();
        }
        else if (ls.getSymCour()=="tantque"){
            instTq();
        }
        else if (ls.getSymCour()=="repeter"){
            instRepeter();
        }
        else if (ls.getSymCour()=="lire"){
            instLire();
        }
        else if (ls.getSymCour()=="ecrire"){
            instEcrire();
        }
        else if (ls.getSymCour()=="pour"){
            instPour();
        }
        else if (ls.getSymCour()=="switch"){
            instSwitch();
        }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instSi(){
// <instSi> ::= si ( <expBool> ) <seqInst> { sinonsi (<expBool>) <seqInst> }[sinon <seqInst> ] finsi  
        sauterSymCour("si");
        sauterSymCour("(");
        expBool();
        sauterSymCour(")");
        seqInst();
       
        while (ls.getSymCour()=="sinonsi"){
            sauterSymCour("sinonsi");
            sauterSymCour("(");
            expBool();
            sauterSymCour(")");
            seqInst();
        }
        if (ls.getSymCour()=="sinon"){
            sauterSymCour("sinon");
            seqInst();
        }
       sauterSymCour("finsi"); 
    
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instTq(){
 // <instTq> ::=tantque (<expBool> ) <seqInst> fintantque

        sauterSymCour("tantque");
        sauterSymCour("(");
        expBool();
        sauterSymCour(")");
        seqInst();
        sauterSymCour("fintantque"); 
    
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instRepeter(){
// <instRepeter> ::= repeter <seqInst> jusqua (<expBool> ) 
        sauterSymCour("repeter");
        seqInst();
        sauterSymCour("jusqua");
        sauterSymCour("(");
        expBool();
        sauterSymCour(")");     
}
 ////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecTable::instSwitch(){  
//      switch ( <variable> ) {case valeur: si <variable> == valeur break;
//      default:  si <variable> si la variable n'est égale a aucune variable  break;}
        sauterSymCour("switch");
        sauterSymCour("(");
        //sauterSymCour("<VARIABLE>");
        testerSymCour("<VARIABLE>");
	ts.chercheAjoute(ls.getSymCour());
        ls.suivant();
        sauterSymCour(")");
        while (ls.getSymCour()=="case"){
            sauterSymCour("case");
            //sauterSymCour("<ENTIER>");
            testerSymCour("<ENTIER>");
            ts.chercheAjoute(ls.getSymCour());
            ls.suivant();
            sauterSymCour(":");
            seqInst();
            sauterSymCour("break"); 
            sauterSymCour(";");
         }
        sauterSymCour("default"); 
        sauterSymCour(":");
        seqInst();
        sauterSymCour("break"); 
}

 ////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instLire(){   
// <instLire> ::=lire(<variable>)
        sauterSymCour("lire");
        sauterSymCour("(");
        //sauterSymCour("<VARIABLE>");
        testerSymCour("<VARIABLE>");
	ts.chercheAjoute(ls.getSymCour());
        ls.suivant();
        sauterSymCour(")"); 
    }
    
////////////////////////////////////////////////////////////////////////////////    
void LecteurPhraseAvecTable::instEcrire(){  
// <instEcrire> ::=ecrire(<expression> | <chaine>) 
        sauterSymCour("ecrire");
        sauterSymCour("(");
        if (ls.getSymCour()=="<CHAINE>"){
           //sauterSymCour("<CHAINE>");
                testerSymCour("<CHAINE>");
                ts.chercheAjoute(ls.getSymCour());
                ls.suivant();
        }else expression();
        sauterSymCour(")"); 
    }
    
//////////////////////////////////////////////////////////////////////////////// 
void LecteurPhraseAvecTable::instPour(){
//     <instPour> ::=pour (<affectation>; <expBool>; <affectation> ) <seqInst> finpour
        sauterSymCour("pour");
        sauterSymCour("(");
        affectation();
        sauterSymCour(";");
        expBool();
        sauterSymCour(";");
        affectation();
        sauterSymCour(")");
        seqInst();
        sauterSymCour("finpour"); 
     }

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::affectation() {
// <affectation> ::= <variable> = <expression>

	//sauterSymCour("<VARIABLE>");
	testerSymCour("<VARIABLE>");
	ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
        if (ls.getSymCour()=="="){
                sauterSymCour("=");
                expression();
        }else if (ls.getSymCour()=="++"){
                sauterSymCour("++");
        }else if (ls.getSymCour()=="--"){
                sauterSymCour("--");
        }else if (ls.getSymCour()=="+="){
                sauterSymCour("+=");
                expression();
        }else if (ls.getSymCour()=="-="){
                sauterSymCour("-=");
                expression();
        }else if (ls.getSymCour()=="*="){
                sauterSymCour("*=");
                expression();
        }else if (ls.getSymCour()=="/="){
                sauterSymCour("/=");
                expression();
        }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expression() {
// <expression> ::= <terme> { <opAdd> <terme> }

	terme();
        while (ls.getSymCour()=="+" || ls.getSymCour()=="-") {
                opAdd();
                terme();
        }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::terme() {
// <terme> ::= <facteur> { <opMult> facteur> }

	facteur();
        while (ls.getSymCour()=="*" || ls.getSymCour()=="/") {
                opMult();
                facteur();
        }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::facteur() {
//<facteur> ::= <ENTIER> | <VARIABLE> | <CHAINE> | <opUnaire> <expBool> | ( <expBool> )
        
        if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>" || ls.getSymCour()=="<CHAINE>") {
		ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
        } else if (ls.getSymCour()=="-" || ls.getSymCour()=="non") {
		opUnaire();
		expBool();
	} else if (ls.getSymCour()=="(") {
		ls.suivant();
		expBool();
		sauterSymCour(")");
	} else {
		erreur("<facteur>");
        }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opAdd()
// <opAdd> ::= + | -
{
	if (ls.getSymCour()=="+" || ls.getSymCour()=="-")
		ls.suivant();
	else
		erreur("<opAdd>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opMult()
// <opMult> ::= * | /
{
	if (ls.getSymCour()=="*" || ls.getSymCour()=="/")
		ls.suivant();
	else
		erreur("<opMult>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expBool()
//     <expBool> ::= <expBoolEt> { <opBoolOu> <expBoolEt> }
{
	expBoolEt();
        while (ls.getSymCour()=="ou") {
                opBoolOu();
                expBoolEt();
        }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expBoolEt()
 //     <expBoolEt> ::= <relation> { <opBoolEt> <relation> }
{
	relation();
        while (ls.getSymCour()=="et") {
                opBoolEt();
                relation();
        }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opBoolEt()
//  <opBoolEt> ::= et  
{
	if (ls.getSymCour()=="et")
		ls.suivant();
	else
		erreur("<opBoolEt>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opBoolOu()
//  <opBool> ::= ou 
{
	if (ls.getSymCour()=="ou")
		ls.suivant();
	else
		erreur("<opBoolOu>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::relation()
// <relation> ::= <expression> { <opRel> <expression> }
{
	expression();
        while (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()=="<=" || ls.getSymCour()==">" || ls.getSymCour()==">=") {
                opRel();
                expression();
        }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opRel()
//<opRel> ::= == | != | < | <= | > | >=
{
	if (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()=="<=" || ls.getSymCour()==">" || ls.getSymCour()==">=")
		ls.suivant();
	else
		erreur("<opRel>");
}


////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opUnaire()
// <opUnaire> ::= - | non 
{
	if (ls.getSymCour()=="-" || ls.getSymCour()=="non")
		ls.suivant();
	else
		erreur("<opUnaire>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0); // plus tard, on levera une exception
}
